{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a name=\"top\"></a><img src=\"./source/SpinalHDL.png\" alt=\"SpinalHDL based on Scala\" style=\"width:320px;\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  Before running Spinal HDL code, be sure to load SpinalHDL Libraries  \n",
    "**Note** : This may be a little slow when the first time load, please wait a moment to download Lib from remote."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "val path = System.getProperty(\"user.dir\") + \"/source/load-spinal.sc\"\n",
    "interp.load.module(ammonite.ops.Path(java.nio.file.FileSystems.getDefault().getPath(path)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## RegIf(Rigister Bank Solution)\n",
    " **$\\color{#FF3030}{Note}$**  This feature only available on Spinal1.4.1 and higher\n",
    "### Creat Reg"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import spinal.lib.bus.amba3.apb._\n",
    "import spinal.lib.bus.regif._\n",
    "\n",
    "class RegBankExample extends Component{\n",
    "    val io = new Bundle{\n",
    "      val apb = slave(Apb3(Apb3Config(16,32)))\n",
    "    }\n",
    "    val busSlave = BusInterface(io.apb,(0x0000, 100 Byte), 0)\n",
    "    val M_REG0  = busSlave.newReg(doc=\"REG0\")\n",
    "    val M_REG1  = busSlave.newReg(doc=\"REG1\")\n",
    "    val M_REG2  = busSlave.newReg(doc=\"REG2\")\n",
    "\n",
    "    val M_REGn  = busSlave.newRegAt(address=0x40, doc=\"REGn\")\n",
    "    val M_REGn1 = busSlave.newReg(doc=\"REGn1\")\n",
    "  }\n",
    "showRtl(new RegBankExample)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**it will automatic generate 3 file**\n",
    "\n",
    "- `./rtl/RegBankExample.v`\n",
    "- `./rtl/RegBankExample.html`, open with web-browser and take a look**\n",
    "- `./rtl/RegBankExample.h`, auto generator c Head file"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![B](./source/a.gif)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Creat Field\n",
    "\n",
    " register field suport 28 AccessType \n",
    " \n",
    " Most of these come from UVM\n",
    "\n",
    "| AccessType | Description                                                                     | Status |\n",
    "|------------|---------------------------------------------------------------------------------|--------|\n",
    "| RO         | w: no effect, r: no effect                                                      | UVM    |\n",
    "| RW         | w: as-is, r: no effect                                                          | UVM    |\n",
    "| RC         | w: no effect, r: clears all bits                                                | UVM    |\n",
    "| RS         | w: no effect, r: sets all bits                                                  | UVM    |\n",
    "| WRC        | w: as-is, r: clears all bits                                                    | UVM    |\n",
    "| WRS        | w: as-is, r: sets all bits                                                      | UVM    |\n",
    "| WC         | w: clears all bits, r: no effect                                                | UVM    |\n",
    "| WS         | w: sets all bits, r: no effect                                                  | UVM    |\n",
    "| WSRC       | w: sets all bits, r: clears all bits                                            | UVM    |\n",
    "| WCRS       | w: clears all bits, r: sets all bits                                            | UVM    |\n",
    "| W1C        | w: 1/0 clears/no effect on matching bit, r: no effect                           | UVM    |\n",
    "| W1S        | w: 1/0 sets/no effect on matching bit, r: no effect                             | UVM    |\n",
    "| W1T        | w: 1/0 toggles/no effect on matching bit, r: no effect                          | UVM    |\n",
    "| W0C        | w: 1/0 no effect on/clears matching bit, r: no effect                           | UVM    |\n",
    "| W0S        | w: 1/0 no effect on/sets matching bit, r: no effect                             | UVM    |\n",
    "| W0T        | w: 1/0 no effect on/toggles matching bit, r: no effect                          | UVM    |\n",
    "| W1SRC      | w: 1/0 sets/no effect on matching bit, r: clears all bits                       | UVM    |\n",
    "| W1CRS      | w: 1/0 clears/no effect on matching bit, r: sets all bits                       | UVM    |\n",
    "| W0SRC      | w: 1/0 no effect on/sets matching bit, r: clears all bits                       | UVM    |\n",
    "| W0CRS      | w: 1/0 no effect on/clears matching bit, r: sets all bits                       | UVM    |\n",
    "| WO         | w: as-is, r: error                                                              | UVM    |\n",
    "| WOC        | w: clears all bits, r: error                                                    | UVM    |\n",
    "| WOS        | w: sets all bits, r: error                                                      | UVM    |\n",
    "| W1         | w: first one after ~hard~ reset is as-is, other w have no effects, r: no effect | UVM    |\n",
    "| WO1        | w: first one after ~hard~ reset is as-is, other w have no effects, r: error     | UVM    |\n",
    "| NA         | w: reserved, r: reserved                                                        | New    |\n",
    "| W1P        | w: 1/0 pulse/no effect on matching bit, r: no effect                            | New    |\n",
    "| W0P        | w: 0/1 pulse/no effect on matching bit, r: no effect                            | New    |\n",
    "\n",
    "Automatic field allocate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import spinal.lib.bus.amba3.apb._\n",
    "import spinal.lib.bus.regif._\n",
    "import spinal.lib.bus.regif.AccessType._\n",
    "\n",
    "class RegBankExample extends Component{\n",
    "    val io = new Bundle{\n",
    "      val apb = slave(Apb3(Apb3Config(16,32)))\n",
    "    }\n",
    "  val busSlave = BusInterface(io.apb,(0x0000, 100 Byte), 0)\n",
    "  val M_REG0  = busSlave.newReg(doc=\"REG1\")\n",
    "  val fd0 = M_REG0.field(2 bits, RW, doc= \"fields 0\")\n",
    "  M_REG0.reserved(5 bits)\n",
    "  val fd1 = M_REG0.field(3 bits, RW, doc= \"fields 0\")\n",
    "  val fd2 = M_REG0.field(3 bits, RW, doc= \"fields 0\")\n",
    "  //auto reserved 2 bits\n",
    "  val fd3 = M_REG0.fieldAt(pos=16, 4 bits, RC, doc= \"fields 3\")\n",
    "  //auto reserved 12 bits\n",
    "}\n",
    "showRtl(new RegBankExample)                             "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![B](./source/b.gif)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### confilict detection"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import spinal.lib.bus.amba3.apb._\n",
    "import spinal.lib.bus.regif._\n",
    "import spinal.lib.bus.regif.AccessType._\n",
    "\n",
    "class RegBankExample extends Component{\n",
    "    val io = new Bundle{\n",
    "      val apb = slave(Apb3(Apb3Config(16,32)))\n",
    "    }\n",
    "  val busSlave = BusInterface(io.apb,(0x0000, 100 Byte), 0)\n",
    "  val M_REG1  = busSlave.newReg(doc=\"REG1\")\n",
    "  val r1fd0 = M_REG1.field(16 bits, RW, doc=\"fields 0\")\n",
    "  val r1fd2 = M_REG1.field(16 bits, RW, doc=\"fields 1\")\n",
    "}\n",
    "showRtl(new RegBankExample)   "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import spinal.lib.bus.amba3.apb._\n",
    "import spinal.lib.bus.regif._\n",
    "import spinal.lib.bus.regif.AccessType._\n",
    "\n",
    "class RegBankExample extends Component{\n",
    "    val io = new Bundle{\n",
    "      val apb = slave(Apb3(Apb3Config(16,32)))\n",
    "    }\n",
    "  val busSlave = BusInterface(io.apb,(0x0000, 100 Byte),0 )\n",
    "  val M_REG1  = busSlave.newReg(doc=\"REG1\")\n",
    "  val r1fd0 = M_REG1.field(16 bits, RW, doc=\"fields 0\")\n",
    "  val r1fd2 = M_REG1.fieldAt(pos =16, 2 bits, RW, doc=\"fields 1\")\n",
    "}\n",
    "showRtl(new RegBankExample)   "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Document \n",
    "BusInterface will auto generate Register document, default generate HTML type.\n",
    "![B](./source/regif-gen-doc.png)\n",
    "```scala\n",
    "class RegBankExample extends Component{\n",
    "    val io = new Bundle{\n",
    "      apb = Apb3(Apb3Config(16,32))\n",
    "    }\n",
    "   val busSlave = BusInterface(io.apb,(0x0000, 100 Byte)\n",
    "   val M_REG1  = busSlave.newReg(doc=\"REG1\")\n",
    "   ...\n",
    "}\n",
    "```\n",
    "will auto generate RegBankExample.html under rtl dir,\n",
    "you can also generate manully \n",
    "```scala\n",
    "busSlave.document(\"RegIf.html\")\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Interrupt Example\n",
    "\n",
    "a interrupt Example, there three triggers tx_done,rx_done,frame_end\n",
    "\n",
    "You need manually add interrupt Enable/Mask/Status register interface like this"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class cpInterruptExample extends Component {\n",
    "  val io = new Bundle {\n",
    "    val tx_done, rx_done, frame_end = in Bool()\n",
    "    val interrupt = out Bool()\n",
    "    val apb = slave(Apb3(Apb3Config(16, 32)))\n",
    "  }\n",
    "  val busif = Apb3BusInterface(io.apb, (0x000, 100 Byte))\n",
    "\n",
    "  val M_CP_INT_EN    = busif.newReg(doc=\"cp int enable register\")\n",
    "  val tx_int_en      = M_CP_INT_EN.field(1 bits, RW, doc=\"tx interrupt enable register\")\n",
    "  val rx_int_en      = M_CP_INT_EN.field(1 bits, RW, doc=\"rx interrupt enable register\")\n",
    "  val frame_int_en   = M_CP_INT_EN.field(1 bits, RW, doc=\"frame interrupt enable register\")\n",
    "  val M_CP_INT_MASK  = busif.newReg(doc=\"cp int mask register\")\n",
    "  val tx_int_mask      = M_CP_INT_MASK.field(1 bits, RW, doc=\"tx interrupt mask register\")\n",
    "  val rx_int_mask      = M_CP_INT_MASK.field(1 bits, RW, doc=\"rx interrupt mask register\")\n",
    "  val frame_int_mask   = M_CP_INT_MASK.field(1 bits, RW, doc=\"frame interrupt mask register\")\n",
    "  val M_CP_INT_STATE   = busif.newReg(doc=\"cp int state register\")\n",
    "  val tx_int_state      = M_CP_INT_STATE.field(1 bits, RW, doc=\"tx interrupt state register\")\n",
    "  val rx_int_state      = M_CP_INT_STATE.field(1 bits, RW, doc=\"rx interrupt state register\")\n",
    "  val frame_int_state   = M_CP_INT_STATE.field(1 bits, RW, doc=\"frame interrupt state register\")\n",
    "\n",
    "  when(io.rx_done && rx_int_en(0)){tx_int_state(0).set()}\n",
    "  when(io.tx_done && tx_int_en(0)){tx_int_state(0).set()}\n",
    "  when(io.frame_end && frame_int_en(0)){tx_int_state(0).set()}\n",
    "\n",
    "  io.interrupt := (tx_int_mask(0) && tx_int_state(0)  ||\n",
    "    rx_int_mask(0) && rx_int_state(0) ||\n",
    "    frame_int_mask(0) && frame_int_state(0))\n",
    "}\n",
    "showRtl(new cpInterruptExample)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can find this is a very tedious and repetitive work,   \n",
    "a better way is creat a Factory fucntion by Macros auto complet those work instead manully creat them.\n",
    "```scala\n",
    "io.interrupt := interruptFactory2(busif,\"M_CP\", io.tx_done,io.rx_done,io.frame_end)\n",
    "```\n",
    "![B](./source/regif-gen-int.png)\n",
    "This is much more convenient than manually do that"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class cpInterruptFactoryExample extends Component {\n",
    "  val io = new Bundle {\n",
    "    val tx_done, rx_done, frame_end = in Bool()\n",
    "    val interrupt = out Bool()\n",
    "    val apb = slave(Apb3(Apb3Config(16, 32)))\n",
    "  }\n",
    "  val busif2 = Apb3BusInterface(io.apb, (0x000, 100 Byte))\n",
    "\n",
    "  val tx = io.tx_done\n",
    "  val rx = io.rx_done\n",
    "  val frame = io.frame_end\n",
    "\n",
    "  io.interrupt := InterruptFactory(busif2,\"M_CP\",tx,rx,frame)\n",
    "}\n",
    "showRtl(new cpInterruptFactoryExample)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<iframe src=\"./source/InterruptRegIf2.html\"></iframe> "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Scala",
   "language": "scala",
   "name": "scala"
  },
  "language_info": {
   "codemirror_mode": "text/x-scala",
   "file_extension": ".scala",
   "mimetype": "text/x-scala",
   "name": "scala",
   "nbconvert_exporter": "script",
   "version": "2.12.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
